using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Catastrophe.Common.Properties;

namespace Catastrophe.Common.Extensions
{
	public static class ParamterCheckExtensions
	{
		private static void Require<TException>(bool assertion, string message) where TException : Exception
		{
			if (assertion)
			{
				return;
			}
			if (string.IsNullOrEmpty(message))
			{
				throw new ArgumentNullException("message");
			}
			TException val = (TException)Activator.CreateInstance(typeof(TException), message);
			throw val;
		}

		public static void Required<T>(this T value, Func<T, bool> assertionFunc, string message)
		{
			if (assertionFunc == null)
			{
				throw new ArgumentNullException("assertionFunc");
			}
			ParamterCheckExtensions.Require<Exception>(assertionFunc(value), message);
		}

		public static void Required<T, TException>(this T value, Func<T, bool> assertionFunc, string message) where TException : Exception
		{
			if (assertionFunc == null)
			{
				throw new ArgumentNullException("assertionFunc");
			}
			ParamterCheckExtensions.Require<TException>(assertionFunc(value), message);
		}

		public static void CheckNotNull<T>(this T value, string paramName) where T : class
		{
			ParamterCheckExtensions.Require<ArgumentNullException>(value != null, string.Format(Resources.ParameterCheck_NotNull, paramName));
		}

		public static void CheckNotNullOrEmpty(this string value, string paramName)
		{
			value.CheckNotNull(paramName);
			ParamterCheckExtensions.Require<ArgumentException>(value.Length > 0, string.Format(Resources.ParameterCheck_NotNullOrEmpty_String, paramName));
		}

		public static void CheckNotEmpty(this Guid value, string paramName)
		{
			ParamterCheckExtensions.Require<ArgumentException>(value != Guid.Empty, string.Format(Resources.ParameterCheck_NotEmpty_Guid, paramName));
		}

		public static void CheckNotNullOrEmpty<T>(this IEnumerable<T> collection, string paramName)
		{
			collection.CheckNotNull(paramName);
			ParamterCheckExtensions.Require<ArgumentException>(collection.Any(), string.Format(Resources.ParameterCheck_NotNullOrEmpty_Collection, paramName));
		}

		public static void CheckLessThan<T>(this T value, string paramName, T target, bool canEqual = false) where T : IComparable<T>
		{
			bool assertion = (canEqual ? (value.CompareTo(target) <= 0) : (value.CompareTo(target) < 0));
			string format = (canEqual ? Resources.ParameterCheck_NotLessThanOrEqual : Resources.ParameterCheck_NotLessThan);
			ParamterCheckExtensions.Require<ArgumentOutOfRangeException>(assertion, string.Format(format, paramName, target));
		}

		public static void CheckGreaterThan<T>(this T value, string paramName, T target, bool canEqual = false) where T : IComparable<T>
		{
			bool assertion = (canEqual ? (value.CompareTo(target) >= 0) : (value.CompareTo(target) > 0));
			string format = (canEqual ? Resources.ParameterCheck_NotGreaterThanOrEqual : Resources.ParameterCheck_NotGreaterThan);
			ParamterCheckExtensions.Require<ArgumentOutOfRangeException>(assertion, string.Format(format, paramName, target));
		}

		public static void CheckBetween<T>(this T value, string paramName, T start, T end, bool startEqual = false, bool endEqual = false) where T : IComparable<T>
		{
			bool assertion = (startEqual ? (value.CompareTo(start) >= 0) : (value.CompareTo(start) > 0));
			string message = (startEqual ? string.Format(Resources.ParameterCheck_BetweenNotEqual, paramName, start, end, start) : string.Format(Resources.ParameterCheck_Between, paramName, start, end));
			ParamterCheckExtensions.Require<ArgumentOutOfRangeException>(assertion, message);
			assertion = (endEqual ? (value.CompareTo(end) <= 0) : (value.CompareTo(end) < 0));
			message = (endEqual ? string.Format(Resources.ParameterCheck_BetweenNotEqual, paramName, start, end, end) : string.Format(Resources.ParameterCheck_Between, paramName, start, end));
			ParamterCheckExtensions.Require<ArgumentOutOfRangeException>(assertion, message);
		}

		public static void CheckDirectoryExists(this string directory, string paramName = null)
		{
			directory.CheckNotNull(paramName);
			ParamterCheckExtensions.Require<DirectoryNotFoundException>(Directory.Exists(directory), string.Format(Resources.ParameterCheck_DirectoryNotExists, directory));
		}

		public static void CheckFileExists(this string fileName, string paramName = null)
		{
			fileName.CheckNotNull(paramName);
			ParamterCheckExtensions.Require<FileNotFoundException>(File.Exists(fileName), string.Format(Resources.ParameterCheck_FileNotExists, fileName));
		}
	}
}
